package org.hy.common.android;

import android.Manifest;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.GpsSatellite;
import android.location.GpsStatus;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;

import androidx.core.app.ActivityCompat;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;


/**
 * Android API本身提供的定位功能,也是GPS定位。
 * GPS定位，是基于卫星定位。它受环境影响很大。并且是单向定位，也就是只有你自己知道你的地理坐标。
 *
 * @author ZhengWei(HY)
 */
@TargetApi(Build.VERSION_CODES.CUPCAKE)
@SuppressLint("NewApi")
public class LocationUtil
{

    private static final String TAG = "LocationUtil";

    private static LocationUtil instance;

    private Activity         activity;

    private LocationManager  locationManager;

    private LocationListener locationListener;



    public static synchronized LocationUtil getInstance(Activity i_Activity)
    {
        if ( i_Activity == null )
        {
            return null;
        }

        if ( instance != null)
        {
            return instance;
        }

        instance                 = new LocationUtil();
        instance.activity        = i_Activity;
        instance.locationManager = (LocationManager) instance.activity.getSystemService(Context.LOCATION_SERVICE);
        return instance;
    }



    public static LocationUtil getInstance()
    {
        return instance;
    }



    /**
     * 判断GPS导航是否打开
     *
     * @return
     */
    public boolean isOpenGPS()
    {
        return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
    }



    /**
     * 判断GPS导航是否打开.
     * false：弹窗提示打开,不建议采用在后台强行开启的方式。
     * true:不做任何处理
     * @return
     */
    public void openGPS()
    {

        if (!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER))
        {
            AlertDialog.Builder dialog = new AlertDialog.Builder(this.activity);
            dialog.setMessage("GPS未打开，是否打开?");

            dialog.setPositiveButton("确定", new DialogInterface.OnClickListener() {

                @Override
                public void onClick(DialogInterface dialog, int which) {
                    Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                    // 设置完成后返回到原来的界面
                    activity.startActivityForResult(intent, 0);
                }
            });

            dialog.setNegativeButton("取消", new DialogInterface.OnClickListener() {

                @Override
                public void onClick(DialogInterface dialog, int which) {
                    dialog.dismiss();
                }
            });
            dialog.show();
        }
    }



    /**
     * 开启GPS定位监听器来获取Location信息
     *
     * @param i_MinTime       位置信息更新周期.单位是毫秒
     * @param i_MinDistance   位置变化最小距离：当位置距离变化超过此值时，将更新位置信息
     */
    public void startListenerByGPS(long i_MinTime ,long i_MinDistance)
    {
        this.startListener(LocationManager.GPS_PROVIDER ,i_MinTime ,i_MinDistance);
    }



    /**
     * 开启GPRS定位监听器来获取Location信息
     *
     * @param i_MinTime       位置信息更新周期.单位是毫秒
     * @param i_MinDistance   位置变化最小距离：当位置距离变化超过此值时，将更新位置信息
     */
    public void startListenerByGPRS(long i_MinTime ,long i_MinDistance)
    {
        this.startListener(LocationManager.NETWORK_PROVIDER ,i_MinTime ,i_MinDistance);
    }



    /**
     * 开启定位监听器来获取Location信息
     *
     * @param i_Provider      有GPS_PROVIDER和NETWORK_PROVIDER两种，前者是GPS,后者是GPRS以及WIFI定位
     * @param i_MinTime       位置信息更新周期.单位是毫秒
     * @param i_MinDistance   位置变化最小距离：当位置距离变化超过此值时，将更新位置信息
     */
    public void startListener(String i_Provider ,long i_MinTime ,long i_MinDistance)
    {
        locationListener = new LocationListener() {

            @Override
            public void onLocationChanged(Location location) {
                //位置信息变化时触发
                Log.i(TAG, "纬度：" + location.getLatitude());
                Log.i(TAG, "经度：" + location.getLongitude());
                Log.i(TAG, "海拔：" + location.getAltitude());
                Log.i(TAG, "时间：" + location.getTime());
            }

            @Override
            public void onStatusChanged(String provider, int status, Bundle extras) {
                //GPS状态变化时触发
            }

            @Override
            public void onProviderEnabled(String provider) {
                //GPS禁用时触发
            }

            @Override
            public void onProviderDisabled(String provider) {
                //GPS开启时触发
            }
        };

        /**
         * 绑定监听
         * 参数1，设备：有GPS_PROVIDER和NETWORK_PROVIDER两种，前者是GPS,后者是GPRS以及WIFI定位
         * 参数2，位置信息更新周期.单位是毫秒
         * 参数3，位置变化最小距离：当位置距离变化超过此值时，将更新位置信息
         * 参数4，监听
         * 备注：参数2和3，如果参数3不为0，则以参数3为准；参数3为0，则通过时间来定时更新；两者为0，则随时刷新
         */
        if ( ActivityCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION)   != PackageManager.PERMISSION_GRANTED
          && ActivityCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED )
        {
            return;
        }
        locationManager.requestLocationUpdates(i_Provider, i_MinTime, i_MinDistance, locationListener);
    }



    /**
     * 主动获取Location，通过以下方法获取到的是最后一次定位信息。
     * 注意：Location location=new Location(LocationManager.GPS_PROVIDER)方式获取的location的各个参数值都是为0。
     */
    public Location getLocation()
    {
        if ( ActivityCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION)   != PackageManager.PERMISSION_GRANTED
          && ActivityCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED )
        {
            return null;
        }

        Location v_Location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
        /*
        Log.i(TAG, "纬度："+v_Location.getLatitude());
        Log.i(TAG, "经度："+v_Location.getLongitude());
        Log.i(TAG, "海拔："+v_Location.getAltitude());
        Log.i(TAG, "时间："+v_Location.getTime());
        */
        return v_Location;
    }



    /**
     * 获取GPS状态监听，包括GPS启动、停止、第一次定位、卫星变化等事件。
     */
    public void getStatusListener()
    {
        if ( ActivityCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION)   != PackageManager.PERMISSION_GRANTED
          && ActivityCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED )
        {
            return;
        }

        GpsStatus.Listener listener = new GpsStatus.Listener()
        {
            @Override
            public void onGpsStatusChanged(int event)
            {
                if ( ActivityCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION)   != PackageManager.PERMISSION_GRANTED
                  && ActivityCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED )
                {
                    return;
                }

                if(event==GpsStatus.GPS_EVENT_FIRST_FIX)
                {
                    //第一次定位
                }
                else if(event==GpsStatus.GPS_EVENT_SATELLITE_STATUS)
                {
                    //卫星状态改变
                    GpsStatus gpsStauts= locationManager.getGpsStatus(null); // 取当前状态
                    int maxSatellites = gpsStauts.getMaxSatellites(); //获取卫星颗数的默认最大值
                    Iterator<GpsSatellite> it = gpsStauts.getSatellites().iterator();//创建一个迭代器保存所有卫星
                    int count = 0;
                    while (it.hasNext() && count <= maxSatellites) {
                        count++;
                        GpsSatellite s = it.next();
                    }
                    Log.i(TAG, "搜索到："+count+"颗卫星");
                }
                else if(event==GpsStatus.GPS_EVENT_STARTED)
                {
                    //定位启动
                }
                else if(event==GpsStatus.GPS_EVENT_STOPPED)
                {
                    //定位结束
                }
            }
        };
        //绑定
        locationManager.addGpsStatusListener(listener);
    }



    /**
     * 获取所有卫星状态
     * @return
     */
    public List<GpsSatellite> getGpsStatus()
    {
        if ( ActivityCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION)   != PackageManager.PERMISSION_GRANTED
          && ActivityCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED )
        {
            return null;
        }

        List<GpsSatellite> result = new ArrayList<GpsSatellite>();
        GpsStatus gpsStatus = locationManager.getGpsStatus(null); // 取当前状态
        //获取默认最大卫星数
        int maxSatellites = gpsStatus.getMaxSatellites();
        //获取第一次定位时间（启动到第一次定位）
        int costTime=gpsStatus.getTimeToFirstFix();
        Log.i(TAG, "第一次定位时间:"+costTime);
        //获取卫星
        Iterable<GpsSatellite> iterable=gpsStatus.getSatellites();
        //一般再次转换成Iterator
        Iterator<GpsSatellite> itrator=iterable.iterator();
        int count = 0;
        while (itrator.hasNext() && count <= maxSatellites){
            count++;
            GpsSatellite s = itrator.next();
            result.add(s);
        }
        return result;
    }



    /**
     * 某一个卫星的信息.
     * @param gpssatellite
     */
    public static void getGpsStatelliteInfo(GpsSatellite gpssatellite)
    {

        //卫星的方位角，浮点型数据
        Log.i(TAG, "卫星的方位角："+gpssatellite.getAzimuth());
        //卫星的高度，浮点型数据
        Log.i(TAG, "卫星的高度："+gpssatellite.getElevation());
        //卫星的伪随机噪声码，整形数据
        Log.i(TAG, "卫星的伪随机噪声码："+gpssatellite.getPrn());
        //卫星的信噪比，浮点型数据
        Log.i(TAG, "卫星的信噪比："+gpssatellite.getSnr());
        //卫星是否有年历表，布尔型数据
        Log.i(TAG, "卫星是否有年历表："+gpssatellite.hasAlmanac());
        //卫星是否有星历表，布尔型数据
        Log.i(TAG, "卫星是否有星历表："+gpssatellite.hasEphemeris());
        //卫星是否被用于近期的GPS修正计算
        Log.i(TAG, "卫星是否被用于近期的GPS修正计算："+gpssatellite.hasAlmanac());
    }

}
